package jonaPad;

import java.io.IOException;
import java.io.StreamTokenizer;
import java.io.StringReader;
import Jona.*;

import java.util.Vector;


public class ArgModelChecker {
	private final int VARTOKEN= 1;
	private final int IDTOKEN = 2;
	private final int TXTTOKEN = 3;
	private final int SIGNTOKEN = 4;
	private final int IFVARTOKEN = 5;
	private final int THENVARTOKEN = 6;
	private final int THENTOKEN = 7;
	private final int ASSIGNTOKEN = 8;
	private final int NONE = 20;
	
	public Theory checkModel(String tmp) throws ModelException
	{
		Vector v1 = new Vector();
		Vector v2 = new Vector();
		Theory rt = new Theory();
		StringReader sis = new StringReader(tmp);
		StreamTokenizer st = new StreamTokenizer(sis);
		st.eolIsSignificant(true);
		st.quoteChar(34);
		boolean done = false;
		//String rt ="";
		
		String expectedNextToken = "";
		String tempStatementName = "";
		String tempStatementText = "";
		String tempConsequent = "";
		
		int expectedNextTokenType = VARTOKEN;
		int statementTypeFound = ArgObject.UNDEFINED;
		boolean isConditional = false;
		
		while (! done) {
		    int c = StreamTokenizer.TT_EOF;
		    try {
    		    c = st.nextToken();
    		} catch (IOException e) { break; }
		    switch (c) {
		        case StreamTokenizer.TT_EOF:
		            //rt += "<EOF>" + "\n";
		            done = true;
		            break;
		        case StreamTokenizer.TT_EOL:
		        	if(expectedNextTokenType < NONE)
		        	{
		        		if(expectedNextTokenType==IDTOKEN) throw new ModelException("issue, assumption, undefined or if expected in line " + (st.lineno() -1));
		        		if(expectedNextTokenType==TXTTOKEN) throw new ModelException(" use \"(text)\" to indicate text in line " + (st.lineno() -1));
		        		if(expectedNextTokenType==SIGNTOKEN)
		        		{
		        			throw new ModelException(expectedNextToken + " expected in line " + (st.lineno() -1));
		        		}
		        	}
		        	else
		        	{
		        		if(!isConditional)
		        			v1.add(new NamedStatement(tempStatementName,new Statement(statementTypeFound,tempStatementText)));
		        		else
		        		{
		        			//(int argumentType,Statement antecedent, Statement consequent) {	
		        			boolean found = false;
		        			int i =0;
		        			ArgObject consequent = null;
		        			while(!found && i < v1.size())
		        			{
		        				if(((NamedStatement)v1.get(i)).name.equals(tempConsequent))
		        				{
		        					consequent = ((NamedStatement)v1.get(i)).s1;
		        					found = true;
		        				}
		        				i++;
		        			}
		        			Conditional c1 = new Conditional(statementTypeFound,consequent);
		        			for(int j =0; j < v2.size(); j++)
		        			{
		        				i= 0;
		        				found = false;
		        				while(!found && i < v1.size())
			        			{
			        				if(((NamedStatement)v1.get(i)).name.equals((String)v2.get(j)))
			        				{
			        					c1.addAntecedent(((NamedStatement)v1.get(i)).s1);
			        					found = true;
			        				}
			        				i++;
			        			}
		        			}
		        				
		        			v1.add(new NamedStatement(tempStatementName,c1));		        			
		        		}
		        		//save old thingy
		        		tempStatementName = "";
		        		tempStatementText = "";
		        		tempConsequent = "";
		        		v2.removeAllElements();
		        		isConditional=false;
		        		statementTypeFound = ArgObject.UNDEFINED;
		        		expectedNextTokenType=VARTOKEN;
		        	}
		            break;
		        case StreamTokenizer.TT_WORD:
		        	String word = st.sval.toLowerCase();
		        	switch(expectedNextTokenType)
		        	{
		        		case IDTOKEN:
		        			if(word.equals("issue"))
			        		{
			        			//issue
		        				statementTypeFound = ArgObject.ISSUE;
		        				expectedNextToken = "(";
			        			expectedNextTokenType = SIGNTOKEN;
			        		}
			        		else
			        		{
			        			if(word.equals("assumption"))
			        			{
			        				statementTypeFound = ArgObject.ASSUMPTION;
			        				expectedNextToken = "(";
				        			expectedNextTokenType = SIGNTOKEN;
			        			}
			        			else
			        			{
			        				if(word.equals("undefined"))
			        				{
			        					statementTypeFound = ArgObject.UNDEFINED;
			        					expectedNextToken = "(";	
					        			expectedNextTokenType = SIGNTOKEN;
			        				}
			        				else
			        				{
			        					if(word.equals("if"))
			        					{
			        						isConditional = true;
			        						expectedNextToken = "(";	
						        			expectedNextTokenType = SIGNTOKEN;
			        					}
			        					else
			        					{
			        						throw new ModelException("Use issue, assumption, undefined or if as statement type in line " + st.lineno());
			        					}
			        				}
			        			}
			        		}		
		        		break;
		        		case THENVARTOKEN:
		        			//consequent
		        			String word2 = st.sval;
		        			boolean found = false;
		        		    int	i =0;
		        			while(!found && i < v1.size())
		        			{
		        				if(((NamedStatement)v1.get(i)).name.equals(word2)) found = true;
		        				i++;
		        			}
		        			if(!found) throw new ModelException("Name: " + word2 + " not defined (in line " + st.lineno() + ")");
		        			else
		        			{
		        				//save consequent
		        				tempConsequent = word2;
		        				expectedNextTokenType = NONE;	
		        			}
		        		break;
		        		case VARTOKEN:
		        			word2 = st.sval;
		        			found = false;
		        			i =0;
		        			while(!found && i < v1.size())
		        			{
		        				if(((NamedStatement)v1.get(i)).name.equals(word2)) found = true;
		        				i++;
		        			}
		        			if(found) throw new ModelException("Name already exists (in line " + st.lineno() + ")");
		        			
		        			tempStatementName = word2;
		        			expectedNextToken = "=";
		        			expectedNextTokenType = SIGNTOKEN;
		        		break;
		        		case IFVARTOKEN:
		        			//antecedents
		        			word2 = st.sval;
		        			found = false;
		        			i =0;
		        			while(!found && i < v1.size())
		        			{
		        				if(((NamedStatement)v1.get(i)).name.equals(word2)) found = true;
		        				i++;
		        			}
		        			if(!found) throw new ModelException("Name: " + word2 + " not defined (in line " + st.lineno() + ")");
		        			else
		        			{	
		        				//save antecedent
		        				v2.add(word2);
		        				expectedNextTokenType = SIGNTOKEN;
		        			}
		        		break;
		        		case THENTOKEN:
		        			if(word.equals("then"))
		        			{
		        				expectedNextTokenType = THENVARTOKEN;
		        			}
		        			else
		        			{
		        				throw new ModelException("'then' expected in line "+ st.lineno() );
		        			}
		        			//"next" statement
		        		break;
		        			
		        	}		        	
		        	//rt += "W - '"+st.sval+"'" + "\n";
		            break;
		        case StreamTokenizer.TT_NUMBER:
		           // rt += "N - '"+st.nval+"'" + "\n";
		            break;
		        default:
		            boolean wasQuote = false;
		            //	String qc = "\"";
		            //	for (int k = 0; k < qc.length(); k++) {
		            //		if (c == qc.charAt(k)) {
		            //			  rt += ("Q - '"+st.sval+"'") + "\n";
		             //             wasQuote = true;
		             //           break;
		             //       }
		              //  }
		              if ((c == 0x22) || (c == 0x27)) {
		            	  //System.out.println("" + st.sval);
		            	  //rt += ("Q - '"+st.sval+"'") + "\n";
		            	  if(expectedNextTokenType == TXTTOKEN)
		            	  {
		            		  tempStatementText = st.sval;
		            		  expectedNextTokenType = SIGNTOKEN;
		            		  expectedNextToken = ")";
		            	  }
		            	  wasQuote = true;
		              }
		            	if (! wasQuote)
		            	{
		            		word = "" + (char)(st.ttype);
		            		//not words..
		            		//rt += ("O - '"+(char)(st.ttype)+"'") + "\n";
				        	
		            		switch(expectedNextTokenType)
				        	{     	
				        		case SIGNTOKEN:
				        			//System.out.println("" + word + " " +  expectedNextToken + " " + expectedNextTokenType);
				        			if(word.equals(expectedNextToken) || isConditional)
					        		{
					        			if(word.equals("="))
					        			{
					        				//System.out.println("found =");
					        				expectedNextTokenType = IDTOKEN;
					        			}
					        			else
					        			{
					        				if(word.equals("("))
					        				{
					        					if(isConditional) expectedNextTokenType = IFVARTOKEN;
					        					else expectedNextTokenType = TXTTOKEN;
					        				}
					        				else
					        				{
					        					if(word.equals(","))
					        					{
					        						if(isConditional) expectedNextTokenType = IFVARTOKEN;
					        						else throw new ModelException("Unvalid character in line " + st.lineno());
					        						//check if were in an conditional else give exception
					        					}
					        					else
					        					{
						        					if(word.equals(")"))
						        					{
						        						if(isConditional) expectedNextTokenType = THENTOKEN;
						        						else expectedNextTokenType = NONE;
						        					}
						        					else
						        					{
						        						throw new ModelException("Unvalid character in line " + st.lineno());
						        					}
						        				}
					        				}
					        			}
				        				expectedNextToken ="";	
					        		}
					        		else throw (new ModelException(expectedNextToken + " Expected in line " + st.lineno()));	
				        		break;
				        	}      		
		            	}
		            break;
		    }
		}
		
		//System.out.println("" + v1.size());
		for(int i =0; i < v1.size();i++)
		{
			rt.addStatement(((NamedStatement)v1.get(i)).s1);
		}		
		return rt;
	}
	
}

//wrapper class
class NamedStatement
{
	public ArgObject s1;
	public String name;
	public NamedStatement(String name,ArgObject s1)
	{
		this.s1 = s1;
		this.name = name;
	}
}

